home *** CD-ROM | disk | FTP | other *** search
/ Inside Multimedia 1994 April / Inside Multimedia CD-ROM (April 1994).iso / prg / gs / gssource.exe / GDEVCDJ.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-24  |  20.3 KB  |  650 lines

  1. /* Copyright (C) 1991, 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gdevcdj.c */
  21. /* H-P DeskJet 500C driver (colour) for Ghostscript */
  22. #include <stdlib.h>        /* for rand() */
  23. #include "gdevprn.h"
  24. #include "gdevpcl.h"
  25.  
  26. /***
  27.  *** Note: this driver was contributed by a user, George Cameron:
  28.  ***       please contact g.cameron@biomed.abdn.ac.uk if you have questions.
  29.  ***/
  30.  
  31. /*
  32.  * Note that there are three drivers contained in this code:
  33.  *
  34.  *     1 - cdeskjet:    A slightly updated version of the original
  35.  *                      cdeskjet driver.
  36.  *     2 - cdjcolor:    This is the significant addition - a 24-bit
  37.  *                      Floyd-Steinberg dithering driver, which gives
  38.  *                      excellent quality, but necessarily results in
  39.  *                      slow printing.
  40.  *     3 - cdjmono:     Included purely to give dj500c owners the benefit
  41.  *                      of Mode 9 fast printing with their black cartridge.
  42.  */
  43.  
  44. /* Definitions affecting print quality/speed */
  45.  
  46. #ifndef SHINGLING        /* Interlaced, multi-pass printing */
  47. #define SHINGLING 1        /* 0 = none, 1 = 50%, 2 = 25%, 2 is best &
  48.                  * slowest */
  49. #endif
  50.  
  51. #ifndef DEPLETION        /* 'Intelligent' dot-removal */
  52. #define DEPLETION 1        /* 0 = none, 1 = 25%, 2 = 50%, 1 best for
  53.                  * graphics? */
  54. #endif                /* Use 0 for transparencies */
  55.  
  56. /*
  57.  * You may select a resolution of 75, 100, 150, or 300 DPI. Normally you
  58.  * would do this in the makefile or on the gs command line, not here.
  59.  * 
  60.  * If the preprocessor symbol A4 is defined, the default paper size is the
  61.  * European A4 size; otherwise it is the U.S. letter size (8.5"x11").
  62.  */
  63.  
  64. #define X_DPI_MAX 300
  65. #define Y_DPI_MAX 300
  66.  
  67. #ifndef X_DPI
  68. #  define X_DPI X_DPI_MAX
  69. #endif
  70. #ifndef Y_DPI
  71. #  define Y_DPI Y_DPI_MAX
  72. #endif
  73.  
  74. /*
  75.  * Maximum printing width = 2400 dots = 8"
  76.  *
  77.  * All Deskjets have 1/2" unprintable bottom margin
  78.  */
  79.  
  80. #define PRINT_LIMIT 0.0625    /* 'real' top margin? */
  81.  
  82. /* Margins are left, bottom, right, top. */
  83. #define DESKJET_MARGINS_LETTER  0.25,  0.40, 0.25,  0.40
  84. #define DESKJET_MARGINS_A4      0.134, 0.40, 0.134, 0.25
  85.  
  86. #ifndef A4
  87. #  define WIDTH_10THS           85
  88. #  define HEIGHT_10THS          110
  89. #  define DESKJET_MARGINS       DESKJET_MARGINS_LETTER
  90. #else
  91. #  define WIDTH_10THS           83      /* 210mm */
  92. #  define HEIGHT_10THS          117     /* 297mm */
  93. #  define DESKJET_MARGINS       DESKJET_MARGINS_A4
  94. #endif
  95.  
  96. /* The number of blank lines that make it worthwhile to reposition */
  97. /* the cursor. */
  98. #define MIN_SKIP_LINES 7
  99.  
  100. #define W sizeof(word)
  101. #define I sizeof(int)
  102.  
  103. /* Printer types */
  104. #define DJ500C_COLOUR    0    /* Standard colour, GS internal dithering */
  105. #define DJ500C_COLOUR_FS 1    /* High quality dithering, but can be slow */
  106. #define DJ500C_MONO      2    /* Black ink + mode 9 compression */
  107.  
  108. /* Procedures */
  109. private dev_proc_map_rgb_color (gdev_pcl_true_map_rgb_color);
  110. private dev_proc_map_color_rgb (gdev_pcl_true_map_color_rgb);
  111.  
  112. /* The device descriptors */
  113. private dev_proc_open_device(hp_dj500c_open);
  114. private dev_proc_print_page(cdeskjet_print_page);
  115. private dev_proc_print_page(cdjcolor_print_page);
  116. private dev_proc_print_page(cdjmono_print_page);
  117.  
  118. #define hp_dj500c_procs(proc_map_rgb_color, proc_map_color_rgb)\
  119.   prn_color_matrix_procs(hp_dj500c_open, gdev_pcl_get_initial_matrix,\
  120.              gdev_prn_output_page, gdev_prn_close,\
  121.              proc_map_rgb_color, proc_map_color_rgb)
  122.  
  123. private gx_device_procs cdeskjet_procs =
  124. hp_dj500c_procs(gdev_pcl_3bit_map_rgb_color, gdev_pcl_3bit_map_color_rgb);
  125.  
  126. private gx_device_procs cdjcolor_procs =
  127. hp_dj500c_procs(gdev_pcl_true_map_rgb_color, gdev_pcl_true_map_color_rgb);
  128.  
  129. private gx_device_procs cdjmono_procs =
  130. hp_dj500c_procs(gdev_prn_map_rgb_color, gdev_prn_map_color_rgb);
  131.  
  132. gx_device_printer gs_cdeskjet_device =
  133. prn_device(cdeskjet_procs, "cdeskjet",
  134.        WIDTH_10THS, HEIGHT_10THS,
  135.        X_DPI, Y_DPI,
  136.        0, 0, 0, 0,
  137.        3, cdeskjet_print_page);
  138.  
  139. gx_device_printer gs_cdjcolor_device =
  140. prn_device(cdjcolor_procs, "cdjcolor",
  141.        WIDTH_10THS, HEIGHT_10THS,
  142.        X_DPI, Y_DPI,
  143.        0, 0, 0, 0,
  144.        24, cdjcolor_print_page);
  145.  
  146. gx_device_printer gs_cdjmono_device =
  147. prn_device(cdjmono_procs, "cdjmono",
  148.        WIDTH_10THS, HEIGHT_10THS,
  149.        X_DPI, Y_DPI,
  150.        0, 0, 0, 0,
  151.        1, cdjmono_print_page);
  152.  
  153. /* Forward references */
  154. private int gdev_pcl_mode9compress(P4(int, const byte *, byte *, byte *));
  155. private int hp_dj500c_print_page(P3(gx_device_printer *, FILE *, int));
  156.  
  157. /* Open the printer and set up the margins. */
  158. private int
  159. hp_dj500c_open(gx_device *pdev)
  160. {       /* Change the margins if necessary. */
  161.   static const float m_a4[4] = { DESKJET_MARGINS_A4 };
  162.   static const float m_letter[4] = { DESKJET_MARGINS_LETTER };
  163.   const float _ds *m =
  164.     (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 :
  165.      m_letter);
  166.   pdev->l_margin = m[0];
  167.   pdev->b_margin = m[1];
  168.   pdev->r_margin = m[2];
  169.   pdev->t_margin = m[3];
  170.   return gdev_prn_open(pdev);
  171. }
  172.  
  173. /* ------ Internal routines ------ */
  174.  
  175. /* The DeskJet500C can compress (mode 9, for all versions) */
  176. private int
  177. cdeskjet_print_page(gx_device_printer * pdev, FILE * prn_stream)
  178. {
  179.   return hp_dj500c_print_page(pdev, prn_stream, DJ500C_COLOUR);
  180. }
  181.  
  182. private int
  183. cdjcolor_print_page(gx_device_printer * pdev, FILE * prn_stream)
  184. {
  185.   return hp_dj500c_print_page(pdev, prn_stream, DJ500C_COLOUR_FS);
  186. }
  187.  
  188. private int
  189. cdjmono_print_page(gx_device_printer * pdev, FILE * prn_stream)
  190. {
  191.   return hp_dj500c_print_page(pdev, prn_stream, DJ500C_MONO);
  192. }
  193.  
  194. /* Some convenient shorthand .. */
  195. #define x_dpi    (pdev->x_pixels_per_inch)
  196. #define y_dpi    (pdev->y_pixels_per_inch)
  197. #define height   (pdev->height)
  198. #define t_margin (pdev->t_margin)
  199. #define b_margin (pdev->b_margin)
  200. #define XTRA 12                /* 2 x 6 XTRA values for end-of-line */
  201. #define W_XTRA (XTRA * I / W)    /* in FSdither error buffers */
  202.  
  203. /* Floyd-Steinberg dithering. Often results in a dramatic improvement in
  204.  * subjective image quality, but can also produce dramatic increases in
  205.  * amount of printer data generated and actual printing time!! Mode 9 2D
  206.  * compression is still useful for fairly flat colour or blank areas but its
  207.  * compression is much less effective in areas where the dithering has
  208.  * effectively randomised the dot distribution. This is a first attempt, but
  209.  * it seems to work reasonably well for the images I've tried. */
  210. #define MAXVALUE  0xff
  211. #define THRESHOLD 0x80
  212. #define C 4                /* ought to be 8, but this seems to be too much */
  213. #define FSdither(inP, out, errP, Err, Bit, DD, II, Offset)\
  214.     oldErr = Err;\
  215.     Err = (* DD errP + ((Err * 7 + C) >> 4) + *(DD inP II));\
  216.     if (Err > THRESHOLD) {\
  217.       out |= Bit;\
  218.       Err -= MAXVALUE;\
  219.     }\
  220.     errP[Offset 6] += ((oldErr * 3 + C) >> 4);\
  221.     errP[Offset 3] += ((oldErr * 5 + C) >> 4);\
  222.     * errP II = ((oldErr + C) >> 4);
  223.  
  224. /* Send the page to the printer.  Compress each scan line. */
  225. private int
  226. hp_dj500c_print_page(gx_device_printer * pdev, FILE * prn_stream, int ptype)
  227. {
  228.   /* We round up buffer space to a multiple of 24 bytes because that's the
  229.    * unit of transposition from pixels to planes in 24-bit mode; it's hardly
  230.    * worth trying to save a few bytes by being less generous in other modes. */
  231.   int line_size = gdev_prn_bytes_per_scan_line(pdev);
  232.   int line_size_words = (line_size + W - 1) / W;
  233.   int plane_size = (line_size + 23) / 24;
  234.   int buffer_size = plane_size * 24;
  235.   int paper_size = gdev_pcl_paper_size((gx_device *)pdev);
  236.   int num_comps = pdev->color_info.num_components;
  237.   int depletion = DEPLETION;
  238.   int shingling = SHINGLING;
  239.   int *errors;
  240.   byte *data, *plane_data[3], *prev_plane_data[3], *out_data;
  241.   word *storage, *data_words;
  242.   uint storage_size_words;
  243.  
  244.   switch (ptype) {
  245.   case DJ500C_COLOUR:
  246.     plane_size *= 3;        /* should really have divided by 8, not 24 */
  247.     storage_size_words = plane_size / W * (8 + 3 + 3 + 2);
  248.     /* data, plane, prev_plane, out_data */
  249.     break;
  250.   case DJ500C_COLOUR_FS:
  251.     storage_size_words = plane_size / W * (24 * I + 24 + 3 + 3 + 2) + W_XTRA;
  252.     /* errors, data, plane, prev_plane, out_data, XTRA */
  253.     shingling = 2;        /* this is a maximum-quality mode */
  254.     break;
  255.   case DJ500C_MONO:
  256.     plane_size *= 24;        /* (ie. same as buffer size) */
  257.     storage_size_words = plane_size / W * (1 + 1 + 2);
  258.     /* plane, prev_plane, out_data */
  259.     break;
  260.   }
  261.   storage = (ulong *) gs_malloc(storage_size_words, W, "hp_dj500c_print_page");
  262.   data_words = storage;
  263.  
  264.   if (storage == 0)        /* can't allocate working area */
  265.     return_error(gs_error_VMerror);
  266.   else {
  267.     int i;
  268.     byte *p = data = (byte *) storage;
  269.     if ((ptype == DJ500C_COLOUR) || (ptype == DJ500C_COLOUR_FS)) {
  270.       p += buffer_size;
  271.     }
  272.     if (ptype == DJ500C_COLOUR_FS) {
  273.       errors = (int *)p;
  274.       p += (buffer_size + XTRA) * I;
  275.     }
  276.     for (i = 0; i < num_comps; i++) {
  277.       plane_data[i] = p;
  278.       p += plane_size;
  279.     }
  280.     for (i = 0; i < num_comps; i++) {
  281.       prev_plane_data[i] = p;
  282.       p += plane_size;
  283.     }
  284.     out_data = p;        /* size is plane_size x 2 */
  285.   }
  286.  
  287.   /* Clear temp storage */
  288.   memset(storage, 0, storage_size_words * W);
  289.  
  290.   /* Initialize printer. */
  291.   fputs("\033E", prn_stream);                          /* reset printer */
  292.   fputs("\033*rbC", prn_stream);                      /* end raster graphics */
  293.   fprintf(prn_stream, "\033*t%dR", (int)x_dpi);          /* set resolution */
  294.   fprintf(prn_stream, "\033&l%da0o0e0L", paper_size); /* paper size etc. */
  295.  
  296.   /* set the number of color planes (1 or 3). -3 means CMY in colour mode */
  297.   fprintf(prn_stream, "\033*r-%dU", num_comps);
  298.  
  299.   /* set depletion and shingling levels */
  300.   fprintf(prn_stream, "\033*o%dd%dQ", depletion, shingling);
  301.  
  302.   /* move to top left of printed area */
  303. #define OFFSET (t_margin - PRINT_LIMIT)    /* Offset to print position */
  304.   fprintf(prn_stream, "\033*p0x%dY", (int)(Y_DPI_MAX * OFFSET));
  305.  
  306.   /* select data compression */
  307.   fputs("\033*b9M", prn_stream);/* mode 9 */
  308.  
  309.   /* Start raster graphics.  From now on */
  310.   /* all escape commands start with \033*b, */
  311.   /* so we combine them. */
  312.   fputs("\033*r1A\033*b", prn_stream);
  313.  
  314.   /* Send each scan line in turn */
  315.   {
  316.     int lnum, i;
  317.     int lend = height - (t_margin + b_margin) * y_dpi;
  318.     int num_blank_lines = 0;
  319.     word rmask = ~(word) 0 << (-pdev->width & (W * 8 - 1));
  320.     int c, m, y, cErr, mErr, yErr;
  321.     int going_up = 1;
  322.     byte *cP = plane_data[0], *mP = plane_data[1], *yP = plane_data[2];
  323.     register int *ep = errors + (XTRA / 2);
  324.     register byte *dp = data;
  325.  
  326.     c = m = y = cErr = mErr = yErr = 0;
  327.  
  328.     if (ptype == DJ500C_COLOUR_FS) { /* Randomly seed initial error buffer */
  329.       for (i = 0; i < buffer_size; i++) {
  330.     *ep++ = (rand() % MAXVALUE) >> 4;
  331.       }
  332.       ep = errors + (XTRA / 2);
  333.     }
  334.  
  335.     for (lnum = 0; lnum < lend; lnum++) {
  336.       register word *end_data = data_words + line_size_words;
  337.       gdev_prn_copy_scan_lines(pdev, lnum, data, line_size);
  338.  
  339.       /* Mask off 1-bits beyond the line width. */
  340.       end_data[-1] &= rmask;
  341.  
  342.       /* Remove trailing 0s. */
  343.       while (end_data > data_words && end_data[-1] == 0)
  344.     end_data--;
  345.       if (end_data == data_words) {    /* Blank line */
  346.     num_blank_lines++;
  347.     continue;
  348.       }
  349.       /* Skip blank lines if any */
  350.       if (num_blank_lines > 0) {
  351.     if (num_blank_lines < MIN_SKIP_LINES) {
  352.       /* Moving down from current position */
  353.       /* causes head motion on the DeskJet, so */
  354.       /* if the number of lines is small, */
  355.       /* we're better off printing blanks. */
  356.       fputs("y", prn_stream); /* Clear current and seed rows */
  357.       for (; num_blank_lines; num_blank_lines--)
  358.         fputs("w", prn_stream);
  359.     } else {
  360.       fprintf(prn_stream, "%dy", num_blank_lines);
  361.     }
  362.     memset(prev_plane_data[0], 0, plane_size * num_comps);
  363.     num_blank_lines = 0;
  364.       } {            /* Printing non-blank lines */
  365.     int i, j;
  366.     byte *odp;
  367.  
  368.     /* In colour modes, we have some bit-shuffling to do before */
  369.     /* we can print the data; in FS mode we also have the */
  370.     /* dithering to take care of. */
  371.     switch (ptype) {
  372.     case DJ500C_COLOUR:
  373.  
  374.       /* Transpose the data to get pixel planes. */
  375.       for (i = 0, odp = plane_data[0]; i < buffer_size;
  376.            i += 8, odp++) {    /* The following is for 16-bit
  377.                  * machines */
  378. #define spread3(c)\
  379. { 0, c, c*0x100, c*0x101, c*0x10000L, c*0x10001L, c*0x10100L, c*0x10101L }
  380.         static ulong spr40[8] = spread3(0x40);
  381.         static ulong spr08[8] = spread3(8);
  382.         static ulong spr02[8] = spread3(2);
  383.         register byte *dp = data + i;
  384.         register ulong pword =
  385.         (spr40[dp[0]] << 1) +
  386.         (spr40[dp[1]]) +
  387.         (spr40[dp[2]] >> 1) +
  388.         (spr08[dp[3]] << 1) +
  389.         (spr08[dp[4]]) +
  390.         (spr08[dp[5]] >> 1) +
  391.         (spr02[dp[6]]) +
  392.         (spr02[dp[7]] >> 1);
  393.         odp[0] = (byte) (pword >> 16);
  394.         odp[plane_size] = (byte) (pword >> 8);
  395.         odp[plane_size * 2] = (byte) (pword);
  396.       }
  397.       break;
  398.  
  399.     case DJ500C_COLOUR_FS:
  400.  
  401.       if (going_up) {
  402.         for (i = 0; i < plane_size; i++) {
  403.           byte c, y, m, bitmask;
  404.           int oldErr;
  405.  
  406.           bitmask = 0x80;
  407.           for (c = m = y = j = 0; j < 8; j++) {
  408.         FSdither(dp, c, ep, cErr, bitmask,, ++, -);
  409.         FSdither(dp, m, ep, mErr, bitmask,, ++, -);
  410.         FSdither(dp, y, ep, yErr, bitmask,, ++, -);
  411.         bitmask >>= 1;
  412.           }
  413.           *cP++ = c;
  414.           *mP++ = m;
  415.           *yP++ = y;
  416.         }
  417.       } else {        /* going_down */
  418.         for (i = 0; i < plane_size; i++) {
  419.           byte c, y, m, bitmask;
  420.           int oldErr;
  421.  
  422.           bitmask = 0x01;
  423.           for (c = m = y = j = 0; j < 8; j++) {
  424.         FSdither(dp, y, ep, yErr, bitmask, --,, +);
  425.         FSdither(dp, m, ep, mErr, bitmask, --,, +);
  426.         FSdither(dp, c, ep, cErr, bitmask, --,, +);
  427.         bitmask <<= 1;
  428.           }
  429.           *--cP = c;
  430.           *--mP = m;
  431.           *--yP = y;
  432.         }
  433.       }
  434.       going_up = !going_up;       /* toggle scan direction */
  435.       break;
  436.     } /* switch() DJET500C_COLOUR and DJET500C_COLOUR_FS */
  437.  
  438.     /* Transfer raster graphics */
  439.     /* in the order C, M, Y. */
  440.     for (i = num_comps - 1; i >= 0; i--) {
  441.  
  442.       int out_count = gdev_pcl_mode9compress(plane_size,
  443.                          plane_data[i],
  444.                          prev_plane_data[i],
  445.                          out_data);
  446.  
  447.       fprintf(prn_stream, "%d%c", out_count, "wvv"[i]);
  448.       fwrite(out_data, sizeof(byte), out_count, prn_stream);
  449.     }
  450.       }      /* Printing non-blank lines */
  451.     }     /* for lnum ... */
  452.   }       /* send each scan line in turn */
  453.  
  454.   /* end raster graphics */
  455.   fputs("\033*rbC", prn_stream);
  456.  
  457.   /* reset to monochrome */
  458.   fputs("\033*r1U", prn_stream);
  459.  
  460.   /* eject page */
  461.   fputs("\033&l0H", prn_stream);
  462.  
  463.   /* free temporary storage */
  464.   gs_free((char *) storage, storage_size_words, W, "hp_dj500c_print_page");
  465.  
  466.   return 0;
  467. }
  468.  
  469. /*
  470.  * Mode 9 2D compression for the HP DeskJet 500C. This mode can give
  471.  * very good compression ratios, especially if there are areas of flat
  472.  * colour (or blank areas), and so is 'highly recommended' for colour
  473.  * printing in particular because of the very large amounts of data which
  474.  * can be generated
  475.  */
  476. private int
  477. gdev_pcl_mode9compress(int bytecount, const byte * current, byte * previous, byte * compressed)
  478. {
  479.   register const byte *cur = current;
  480.   register byte *prev = previous;
  481.   register byte *out = compressed;
  482.   const byte *end = current + bytecount;
  483.  
  484.   while (cur < end) {        /* Detect a run of unchanged bytes. */
  485.     const byte *run = cur;
  486.     register const byte *diff;
  487.     int offset;
  488.     while (cur < end && *cur == *prev) {
  489.       cur++, prev++;
  490.     }
  491.     if (cur == end)
  492.       break;            /* rest of row is unchanged */
  493.     /* Detect a run of changed bytes. */
  494.     /* We know that *cur != *prev. */
  495.     diff = cur;
  496.     do {
  497.       *prev++ = *cur++;
  498.     }
  499.     while (cur < end && *cur != *prev);
  500.     /* Now [run..diff) are unchanged, and */
  501.     /* [diff..cur) are changed. */
  502.     offset = diff - run;
  503.     {
  504.       const byte *stop_test = cur - 4;
  505.       int dissimilar, similar;
  506.  
  507.       while (diff < cur) {
  508.     const byte *compr = diff;
  509.     const byte *next;    /* end of run */
  510.     byte value;
  511.     while (diff <= stop_test &&
  512.            ((value = *diff) != diff[1] ||
  513.         value != diff[2] ||
  514.         value != diff[3]))
  515.       diff++;
  516.  
  517.     /* Find out how long the run is */
  518.     if (diff > stop_test)    /* no run */
  519.       next = diff = cur;
  520.     else {
  521.       next = diff + 4;
  522.       while (next < cur && *next == value)
  523.         next++;
  524.     }
  525.  
  526. #define MAXOFFSETU 15
  527. #define MAXCOUNTU 7
  528.     /* output 'dissimilar' bytes, uncompressed */
  529.     if ((dissimilar = diff - compr)) {
  530.       int temp, i;
  531.  
  532.       if ((temp = --dissimilar) > MAXCOUNTU)
  533.         temp = MAXCOUNTU;
  534.       if (offset < MAXOFFSETU)
  535.         *out++ = (offset << 3) | (byte) temp;
  536.       else {
  537.         *out++ = (MAXOFFSETU << 3) | (byte) temp;
  538.         offset -= MAXOFFSETU;
  539.         while (offset >= 255) {
  540.           *out++ = 255;
  541.           offset -= 255;
  542.         }
  543.         *out++ = offset;
  544.       }
  545.       if (temp == MAXCOUNTU) {
  546.         temp = dissimilar - MAXCOUNTU;
  547.         while (temp >= 255) {
  548.           *out++ = 255;
  549.           temp -= 255;
  550.         }
  551.         *out++ = (byte) temp;
  552.       }
  553.       for (i = 0; i <= dissimilar; i++)
  554.         *out++ = *compr++;
  555.       offset = 0;
  556.     }            /* end uncompressed */
  557. #define MAXOFFSETC 3
  558. #define MAXCOUNTC 31
  559.     /* output 'similar' bytes, run-length encoded */
  560.     if ((similar = next - diff)) {
  561.       int temp;
  562.  
  563.       if ((temp = (similar -= 2)) > MAXCOUNTC)
  564.         temp = MAXCOUNTC;
  565.       if (offset < MAXOFFSETC)
  566.         *out++ = 0x80 | (offset << 5) | (byte) temp;
  567.       else {
  568.         *out++ = 0x80 | (MAXOFFSETC << 5) | (byte) temp;
  569.         offset -= MAXOFFSETC;
  570.         while (offset >= 255) {
  571.           *out++ = 255;
  572.           offset -= 255;
  573.         }
  574.         *out++ = offset;
  575.       }
  576.       if (temp == MAXCOUNTC) {
  577.         temp = similar - MAXCOUNTC;
  578.         while (temp >= 255) {
  579.           *out++ = 255;
  580.           temp -= 255;
  581.         }
  582.         *out++ = (byte) temp;
  583.       }
  584.       *out++ = value;
  585.       offset = 0;
  586.     }            /* end compressed */
  587.     diff = next;
  588.       }
  589.     }
  590.   }
  591.   return out - compressed;
  592. }
  593.  
  594. /* Map a r-g-b color to a color index. */
  595. /* We complement the colours, since we're using cmy anyway, */
  596. /* and because the buffering routines expect white to be zero. */
  597. private gx_color_index
  598. gdev_pcl_true_map_rgb_color(gx_device * dev, gx_color_value r,
  599.                 gx_color_value g, gx_color_value b)
  600. {
  601.   if ((r & g & b) == 0xff)
  602.     return (gx_color_index)0;   /* white */
  603.   else
  604.     return (gx_color_value_to_byte(r) +
  605.         ((uint) gx_color_value_to_byte(g) << 8) +
  606.         ((ulong) gx_color_value_to_byte(b) << 16)) ^ 0xffffff;
  607. }
  608.  
  609. /* Map a color index to a r-g-b color. */
  610. /* Includes colour balancing, following HP recommendations, to try */
  611. /* and correct the greenish cast resulting from an equal mix of the */
  612. /* c, m, y, inks to give a truer black. */
  613. /* Someday we can add gamma-lookup tables as well */
  614. private int
  615. gdev_pcl_true_map_color_rgb(gx_device * dev, gx_color_index color,
  616.                 gx_color_value prgb[3])
  617. {
  618.   /* NB. We actually have cmy colours, from the way we set up the */
  619.   /* mapping rgb_color */
  620.   int c = (int)(color >> 16);
  621.   int m = (int)((color >> 8) & 0xff);
  622.   int y = (int)(color & 0xff);
  623.   if ((c & m & y) == 0)    /* white */
  624.     return 0;
  625.   else {
  626.     int maxval, minval, range;
  627.  
  628.     maxval = c >= m ? c : m;
  629.     maxval = maxval >= y ? maxval : y;
  630.     if (maxval > 0) {
  631.       minval = c <= m ? c : m;
  632.       minval = minval <= y ? minval : y;
  633.       range = maxval - minval;
  634.  
  635. #define CORRECTION 4  /* ie. 4/5 reduction in cyan to get true black */
  636.       c = ((long)(c << 1) + (range + (long)(maxval * CORRECTION)) + 1) /
  637.     (long)(maxval * ((CORRECTION + 1) << 1));
  638.       
  639.       prgb[0] = (gx_color_value)c;
  640.       prgb[1] = (gx_color_value)m;
  641.       prgb[2] = (gx_color_value)y;
  642.     }
  643.   }
  644.   return 0;
  645. }
  646.  
  647. #undef t_margin
  648. #undef b_margin
  649. #undef height
  650.